package com.im.immodel;

import static com.hotpot.sdk.utils.ConstantsKt.ADD_SESSION_TO_SESSION_LIST;
import static com.hotpot.sdk.utils.ConstantsKt.CURRENT_SESSION;
import static com.hotpot.sdk.utils.ConstantsKt.GROUP;
import static com.hotpot.sdk.utils.ConstantsKt.SESSION_LIST;

import android.app.Application;
import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelStoreOwner;

import com.alibaba.android.arouter.launcher.ARouter;
import com.hotpot.core.Hotpot;
import com.hotpot.core.config.HotpotConfig;
import com.hotpot.core.interfaces.IMessageCallBack;
import com.hotpot.sdk.HotpotManager;
import com.hotpot.sdk.config.HotpotManagerConfig;
import com.hotpot.sdk.room.entity.receive.SessionListReceive;
import com.hotpot.sdk.utils.RoomDaoHelper;
import com.hotpot.uikit.talk.MessageListFragment;
import com.hotpot.uikit.talk.config.IMUikitManager;
import com.hotpot.uikit.talk.model.TalkingListViewModel;
import com.hotpot.uikit.utils.qrcode.QRCodeResultPresenter;
import com.im.immodel.config.IMListConfigPresenter;
import com.im.immodel.config.IMMsgActionConfig;
import com.im.immodel.config.IMMsgLongPopActionPresenter;
import com.im.immodel.config.IMRecyclerConfigPresenter;
import com.im.immodel.config.IMViewHolderPresenter1;
import com.netease.biz_video_group.yunxin.voideoGroup.MeetingConfig;
import com.netease.biz_video_group.yunxin.voideoGroup.viewmodel.MeetingGlobViewModel;
import com.netease.nimlib.sdk.NIMClient;
import com.netease.nimlib.sdk.SDKOptions;
import com.netease.nimlib.sdk.StatusBarNotificationConfig;
import com.netease.nimlib.sdk.auth.AuthService;
import com.netease.nimlib.sdk.auth.LoginInfo;
import com.qgb.zcore.api.IPathProvider;
import com.qgb.zcore.api.UrlConfig;
import com.qgb.zcore.api.UrlConfigCall;
import com.qgb.zcore.api.interceptor.TokenHeaderInterceptor;
import com.qgb.zcore.mmkvutil.CacheMarker;
import com.qgb.zcore.mmkvutil.MkvUtils;
import com.qgb.zcore.qrcode.QRCodeResultHelper;
import com.qgb.zcore.router.ContactsRouterPath;
import com.qgb.zcore.router.IMRouterPath;
import com.qgb.zcore.router.SearchRouter;
import com.qgb.zutils.JsonUtils;
import com.qgb.zutils.LogUtils;
import com.qgb.zutils.ThreadUtils;
import com.swgk.core.BaseAppApplication;
import com.swgk.core.BuildConfig;
import com.swgk.core.download.HttpUtil;
import com.swgk.core.util.MLog;
import com.zjkj.preset.ContextHelper;
import com.zjkj.preset.app.ViewModelHelper;
import com.zjkj.preset.net.NetWorkConfig;
import com.zjkj.qgb.contacts.ContactsConfigure;
import com.zjkj.qgb.contacts.ui.employee_card.IMViewModel;
import org.jetbrains.annotations.NotNull;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;

/*
 * IM工具类
 * IM初始化配置，监听信息配置
 * 跳转界面配置
 * 相关文件(IMMsgActionConfig(会话功能配置), ContactBookActivity(通讯录承载类))
 * */
public class IMUtils {

    private static IMUtils mInstance;
    private TalkingListViewModel talkingListViewModel;
    private MessageListFragment messageListFragment;

    private boolean isDebug = BuildConfig.BUILD_TYPE.equals("debug") ? true : false;

    private final static long CONNECT_TIMEOUT = 60;//超时时间，秒
    private final static long READ_TIMEOUT = 60;//读取时间，秒
    private final static long WRITE_TIMEOUT = 60;//写入时间，秒

    public static IMUtils getInstance() {
        if (null == mInstance) {
            synchronized (HttpUtil.class) {
                if (null == mInstance) {
                    mInstance = new IMUtils();
                }
            }
        }
        return mInstance;
    }

    /**
     * IM 初始化，必须在App启动的时候调用同步 Application
     *
     * @param appApplication
     */
    public void initContext(BaseAppApplication appApplication) {
//        long time = System.currentTimeMillis();
        //初始化IM全局使用的Application实例对象
        ContextHelper.init(appApplication);
        //消息通知过滤和分发初始化
        initHotpotManagerConfig();
        //视频会话,视频会议,音频初始化
        initMeeting(appApplication);
//        LogUtils.d("IMUtils","初始化：" + (System.currentTimeMillis() - time));
    }

    /**
     * IM 消息长连接初始化
     * 收到的消息过滤和分发
     */
    private void initHotpotManagerConfig() {
//        long time = System.currentTimeMillis();
        //过滤企管帮相关信息
        Map<String, String> filterMap = new HashMap<>();
        filterMap.put("jingyingbang_client", "jingyingbang_client");
        filterMap.put("jingyingbang_pc", "jingyingbang_pc");
        filterMap.put("jingyingbang_android", "jingyingbang_android");
        filterMap.put("jingyingbang_ios", "jingyingbang_ios");

        HotpotManagerConfig hotpotManagerConfig = HotpotManagerConfig.build()
                .setDebug(isDebug)
                .setFilterMsg(filterMap)
                .setHttpClient(new OkHttpClient.Builder()  //解决Android 10上获取信任凭证问题
                        .sslSocketFactory(createSSLSocketFactory(), createX509TrustManager()).build())
                .setFilteringPlatformListener(new HotpotConfig.FilteringPlatformListener() {
                    @Override
                    public boolean filteringPlatform(@Nullable String type, @Nullable String platform) {
                        boolean isResult = true;
                        switch (type) {
                            case GROUP:
                                isResult = (!TextUtils.equals("zjkf_customer_pc", platform)
                                        && !TextUtils.equals("zjkf_pc_browser", platform)
                                        && !TextUtils.equals("zjkf_service_pc", platform));
                                break;
                            case CURRENT_SESSION:
                            case ADD_SESSION_TO_SESSION_LIST:
                                isResult = TextUtils.equals("jingyingbang_android", platform);
                                break;
                            case SESSION_LIST:
                                isResult = (TextUtils.equals("jingyingbang_android", platform)
                                        || TextUtils.equals("jingyingbang_client", platform)
                                        || TextUtils.equals("jingyingbang_ios", platform)
                                        || TextUtils.equals("jingyingbang_pc", platform)
                                        || TextUtils.equals("all", platform));
                                break;
                        }
                        return isResult;
                    }
                })
                .create();
        HotpotManager.getInstance().initHotpot(ContextHelper.getApplication(), hotpotManagerConfig);
//        LogUtils.d("IMUtils","IM通知过滤监听：" + (System.currentTimeMillis() - time));
    }

    /**
     * 初始化IM视频会议，音频会话等
     */
    public void initMeeting(Application application) {
//        NIMClient.initSDK();
        String account = MkvUtils.get().getString(MkvUtils.UserData, CacheMarker.ImAccount, "");
        String token = MkvUtils.get().getString(MkvUtils.UserData, CacheMarker.NimToken, "");
        Log.e("lal", "initMeeting: " + account + "token:" + token);
        if (TextUtils.isEmpty(account) || TextUtils.isEmpty(token)) {
            // 本地保存数据不全时，登录信息为null，登陆时登录网易号
            NIMClient.init(ContextHelper.getApplication(), null, options(ContextHelper.getApplication()));
        } else {
            // 本地数据保存齐全，初始化时添加登录信息
            NIMClient.init(ContextHelper.getApplication(),
                    new LoginInfo(account, token),
                    options(ContextHelper.getApplication()));

        }
        MeetingConfig.INSTANCE.init(application);
//        MeetingConfig.INSTANCE.addStateListener(new AVCFromMeetingListener());
        //MeetingConfig.INSTANCE.addStateListener(new IMFromMeetingListener());
        LogUtils.i("---Meeting初始化完毕---");
    }

    // 如果返回值为 null，则全部使用默认参数。
    private SDKOptions options(Application application) {
        SDKOptions options = new SDKOptions();

        // 如果将新消息通知提醒托管给 SDK 完成，需要添加以下配置。否则无需设置。
        StatusBarNotificationConfig config = new StatusBarNotificationConfig();
//        Class<?> destination = RouteHelper.INSTANCE.getActivityClassPostcard(CommonRouterPath.MainActivity).getDestination();
//        config.notificationEntrance = (Class<? extends Activity>) destination; // 点击通知栏跳转到该Activity
        config.notificationSmallIconId = R.mipmap.ic_launcher_round;
        // 呼吸灯配置
        config.ledARGB = Color.GREEN;
        config.ledOnMs = 1000;
        config.ledOffMs = 1500;
        // 通知铃声的uri字符串
//        config.notificationSound = "android.resource://com.netease.nim.demo/raw/msg";
        options.statusBarNotificationConfig = config;

        // 配置保存图片，文件，log 等数据的目录
        // 如果 options 中没有设置这个值，SDK 会使用采用默认路径作为 SDK 的数据目录。
        // 该目录目前包含 log, file, image, audio, video, thumb 这6个目录。
        //String sdkPath = getAppCacheDir(application) + "/nim"; // 可以不设置，那么将采用默认路径
        // 如果第三方 APP 需要缓存清理功能， 清理这个目录下面个子目录的内容即可。
        //options.sdkStorageRootPath = sdkPath;

        // 配置是否需要预下载附件缩略图，默认为 true
        options.preloadAttach = true;
        options.asyncInitSDK = true; //开启异步初始化云信
        options.reducedIM = true; //开启异步初始化云信

        // 配置附件缩略图的尺寸大小。表示向服务器请求缩略图文件的大小
        // 该值一般应根据屏幕尺寸来确定， 默认值为 Screen.width / 2
        //   options.thumbnailSize = ${Screen.width} / 2;

        //options.mixPushConfig = buildMixPushConfig();

        return options;
    }

    /**
     * 初始化IM会话和网络
     * 优化：在登录后再初始化
     */
    public void initManager(ViewModelStoreOwner viewModelStoreOwner, ListSessionUnRead listSessionUnRead) {
//        long time = System.currentTimeMillis();
        //删除IM数据库表文件，解决IM版本迭代导致的数据库表结构变化导致的报错
//        IMDBUtils.getInstance().deleteDB();
        //初始化IM全局使用的Application实例对象
        ThreadUtils.runOnSubThread(() -> RoomDaoHelper.getInstaner().deleteDB(ContextHelper.getApplication()));
        initHotpotManagerConfig();
        //配置IM会话内添加的功能模块
        IMUikitManager.withImProxy()
                //IM会话底部内容配置
                .setMsgActionListProxy(new IMMsgActionConfig())
                .setMsgLongPopProxy(new IMMsgLongPopActionPresenter())
                .setOpenDoc(false)
                .setOpenDing(false)
                .setOpenTalkingRigthPopMenu(true)
                .setVideoViewManager()
//                .setTalkingDetailProxy(new TalkingDetailsPresenter())
                .setMessageListProxy(new IMListConfigPresenter())
                //会话列表消息内容
                .setIMRecyclerProxy(new IMRecyclerConfigPresenter())
                .setImViewHoldersProxy(new IMViewHolderPresenter1())
                .setSlidingSettings(true, true, true);

        //二维码识别结果处理
        QRCodeResultHelper.getInstance().getConfig().setQrCodeResultProxy(new QRCodeResultPresenter());

        //配置IM网络配置
        initNetWork();
        //配置隐藏IM相关未开发内容
        initContactBook();
        // MainActivity内开启IM监听(判断登录状态)
        initMsgListener(viewModelStoreOwner, listSessionUnRead);
    }

    /**
     * 消息通知管理坚听初始化
     *
     * @param viewModelStoreOwner
     */
    public void initMessage(ViewModelStoreOwner viewModelStoreOwner) {
        if (talkingListViewModel == null) {
            talkingListViewModel = new ViewModelProvider(viewModelStoreOwner, new ViewModelProvider.AndroidViewModelFactory(ContextHelper.getApplication())).get(TalkingListViewModel.class);
            talkingListViewModel.getRefresh();
        }
        //获取缓存的IM账号
        talkingListViewModel.account = MkvUtils.get().getString(MkvUtils.UserData, CacheMarker.ImAccount, "");
        if (!TextUtils.isEmpty(talkingListViewModel.account)) {
            if (Hotpot.Companion.getInstance().isOpenAndConnect(talkingListViewModel.account)) {
                HotpotManager.getInstance().stopHotpot();
            }

            String string = MkvUtils.get().getString(MkvUtils.UserData, CacheMarker.LoginToken, "");
            String url = String.format(UrlConfig.getSingleton().getIMWSUrl().replace("android", "jingyingbang_android"), string, talkingListViewModel.account);
            HotpotManager.getInstance().startHotpot(url, talkingListViewModel.account);
            talkingListViewModel.addMsgListener();
            talkingListViewModel.addAVChatListener();
        }
    }

    /**
     * 加载消息数据列表
     */
    public MessageListFragment getChatManager() {
        if (messageListFragment == null) {
            messageListFragment = new MessageListFragment();
        }
        return messageListFragment;
    }

    /**
     * 刷新数据库，以及消息通知
     */
    public void refreshMessage() {
        if (talkingListViewModel != null) {
            ThreadUtils.runOnSubThread(() -> {
                talkingListViewModel.getTalkingList();
                RoomDaoHelper.getInstaner().getSessionListDao().listTopSession();
            });
        }
    }

    /*
     * 初始化通讯录
     */
    public void initContactBook() {
//        long time = System.currentTimeMillis();
        ContactsConfigure.getInstance().setOneClickCall(false);
        ContactsConfigure.getInstance().setOversee(false);
        ContactsConfigure.getInstance().setSecretChat(false);
        ContactsConfigure.getInstance().setContactsSearch(false);
    }

    /*
     * MainActivity内开启IM监听(判断登录状态)
     */
    private void initMsgListener(ViewModelStoreOwner viewModelStoreOwner, ListSessionUnRead listSessionUnRead) {
//        long time = System.currentTimeMillis();
        initMessage(viewModelStoreOwner);
        //注册未读消息监听统计
        RoomDaoHelper.getInstaner().getSessionListDao().listSessionUnRead(false).observeForever(sessionListReceives -> {
            int num = 0;
            for (SessionListReceive sessionListReceive : sessionListReceives) {
                num = sessionListReceive.getUnReadNum() + num;
            }
            if (listSessionUnRead != null) {
                listSessionUnRead.onChanged(num);
            }
        });
//        LogUtils.d("IMUtils","IM注册未读消息监听：" + (System.currentTimeMillis() - time));
    }

    /**
     * IM 网络初始化
     */
    public void initNetWork() {
        //BuildConfig.BUILD_TYPE.equals("release") false为正式环境  true 为测试环境
        UrlConfig.getSingleton().init(isDebug); //IM初始化，并配置log日志级别
        //配置根据当前运行环境来切换对应域名
        UrlConfig.getSingleton().changeConfig(BuildConfig.BUILD_TYPE);
        UrlConfigCall urlConfigCall = new UrlConfigCall() {
            @Override
            public void onChange(UrlConfig urlConfig, String configKey, Map<String, String> urls) {
                NetWorkConfig.Config config = new NetWorkConfig.Config();
                //默认给Header添加Token拦截器
                config.addInterceptor(new TokenHeaderInterceptor());
                // 请求完成后检验Token是否失效
//                config.addInterceptor(new TokenVerifyInterceptor());
                config.setDebug(isDebug);
                NetWorkConfig.getSingleton().init(UrlConfig.getSingleton().getBaseUrl(), config);
            }
        };
        Map.Entry<String, Class<? extends IPathProvider>> currentPathProvider = UrlConfig.getSingleton().getCurrentPathProvider();
        urlConfigCall.onChange(UrlConfig.getSingleton(), currentPathProvider.getKey(), UrlConfig.getSingleton().getProvider());
        UrlConfig.getSingleton().addUrlConfigCall(urlConfigCall);
    }

    /*
     * 登录后保存用户状态信息
     */
    public void saveLoginUserInfo(String imAccount, String token, String imToken, String resourcePCToken, String resourceAPPToken) {
        MkvUtils.get().putString(MkvUtils.UserData, CacheMarker.LoginToken, resourcePCToken);
        MkvUtils.get().putString(MkvUtils.UserData, CacheMarker.ImAccount, imAccount);
        MkvUtils.get().putString(MkvUtils.UserData, CacheMarker.NimToken, imToken);
        MkvUtils.get().putString(MkvUtils.UserData, CacheMarker.ResourcePCToken, resourcePCToken);
        MkvUtils.get().putString(MkvUtils.UserData, CacheMarker.ResourceAPPToken, resourceAPPToken);
        MkvUtils.get().putString(MkvUtils.UserData, CacheMarker.WebViewToken, token);
        NIMClient.getService(AuthService.class).login(new LoginInfo(imAccount, imToken));
    }

    /*
     * 保存用户的企业NO
     */
    public void saveUserCurrentCompanyNo(String companyNo) {
        MkvUtils.get().putString(MkvUtils.UserData, CacheMarker.CurrentEnterpriseNo, companyNo);
    }

    public void saveIMUserId(String userId, String realName) {
        MkvUtils.get().putString(MkvUtils.UserData, CacheMarker.UserId, userId);
        MkvUtils.get().putString(MkvUtils.UserData, CacheMarker.RealName, realName);
        MkvUtils.get().putString(MkvUtils.UserData, CacheMarker.UserName, realName);
    }

    public void saveIMUserLogo(String avatar) {
        if (!TextUtils.isEmpty(avatar))
            MkvUtils.get().putString(MkvUtils.UserData, CacheMarker.UserIcon, avatar);
    }

    /*
     * 退出登录后清空用户状态信息
     */
    public void clearLoginUserInfo() {
        MkvUtils.get().clear(MkvUtils.UserData);
        HotpotManager.getInstance().stopHotpot();
        ThreadUtils.runOnSubThread(() -> RoomDaoHelper.getInstaner().deleteDB(ContextHelper.getApplication()));
        ViewModelHelper.get(ContextHelper.getApplication(), MeetingGlobViewModel.class).resetMeetingConfig();
        //网易IM退出
        NIMClient.getService(AuthService.class).logout();
        talkingListViewModel = null;
    }

    /*
     * 消息指令拦截处理
     * index: 1 账户密码修改指令提示  2 经营帮通知消息数目刷新
     * */
    public void handleNewsInterception(int index, MsgHandleInterception handleInterception) {
        HotpotManager.getInstance().addMsgListener(new IMessageCallBack() {
            @Override
            public void onConnectSuccess(int i, @Nullable String s) {

            }

            @Override
            public void onConnectFailed(int i, @Nullable String s) {

            }

            @Override
            public void onClosing(int i, @Nullable String s) {

            }

            @Override
            public void onClosed(int i, @Nullable String s) {

            }

            @Override
            public void onMessage(@Nullable String cmdType, @Nullable String content, @Nullable String s2) {
                if (index == 1) {
                    if ("CHANGE_PASSWORD".equals(cmdType)) {
                        handleInterception.onChangedPassword();
                    }
                } else if (index == 2) {
                    if (TextUtils.equals(cmdType, "P2P")) {
                        Map map = JsonUtils.toMap(content);
                        String sender = (String) map.get("sender");
                        if (!TextUtils.isEmpty(sender) && "IM_SYSTEM_ACCOUNT_TOTAL".equals(sender))
                            handleInterception.onRefreshUnRead();
                            refreshMessage();
                    }
                }
            }

            @Override
            public void onError(int i, @Nullable String s, @Nullable String s1) {

            }
        });
    }

    //路由界面跳转---------------------------------------------------------------------

    /*
     * 搜索界面
     * */
    public void startSearch() {
        ARouter.getInstance()
                .build(SearchRouter.GlobalSearch)
                .navigation();
    }

    /*
     * 群聊界面
     * */
    public void startGroupChat() {
        ARouter.getInstance()
                .build(IMRouterPath.StartGroupChat)
                .navigation();
    }

    /*
     * 好友界面
     * */
    public void startFriend() {
        ARouter.getInstance()
                .build(ContactsRouterPath.ADD_FRIENDS)
                .navigation();
    }

    /*
     * 扫一扫添加好友/员工卡片界面
     * */
    public void startEmployeeCard(String result) {
        ARouter.getInstance()
                .build(ContactsRouterPath.PersonCardCompany)
                .withString("fromImAccount", result.replace("friend:", ""))
                .withString("sourceType", "2")
                .navigation();
    }

    /*
     * 扫一扫群聊二维码/群申请界面
     * */
    public void startGroupApply(String result) {
        String[] split = result.split("@");
        Bundle bundle = new Bundle();
        bundle.putString("groupId", split[1]);
        bundle.putString("imAccount", split[2]);
        ARouter.getInstance()
                .build(IMRouterPath.ScanAddGroup)
                .withBundle("BUNDLE", bundle)
                .navigation();
    }


    /**
     * 返回通讯录封装的Fragment界面
     *
     * @param flag 是否隐藏通讯录的标题
     */
    public Fragment onBackContactBook(boolean flag) {
        Fragment fragment = (Fragment) ARouter.getInstance()
                .build(ContactsRouterPath.mailListHome)
                .navigation();
        if (fragment == null) return null;
        Bundle bundle = new Bundle();
        bundle.putBoolean("isHideTitle", flag);
        fragment.setArguments(bundle);
        return fragment;
    }

    /**
     * 跳转单聊界面
     *
     * @param toAccount 聊天对方的ImAccount
     */
    public void buildSingleTalking(String toAccount) {
        String imAccount = MkvUtils.get().getString(MkvUtils.UserData, CacheMarker.ImAccount, "");
        if (TextUtils.isEmpty(imAccount)) {
            return;
        }
        IMViewModel imViewModel = ViewModelHelper.get(IMViewModel.class);
        imViewModel.buildSingleTalking(imAccount, toAccount, true, false);
    }

    //解决Android 10上获取相关信任凭证---------------------------------------------------
    @NotNull
    private X509TrustManager createX509TrustManager() {
        return new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
    }

    private SSLSocketFactory createSSLSocketFactory() {
        SSLSocketFactory ssfFactory = null;
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{new TrustAllCerts()}, new SecureRandom());

            ssfFactory = sc.getSocketFactory();
        } catch (Exception e) {
        }
        return ssfFactory;
    }

    private class TrustAllCerts implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

    public interface ListSessionUnRead {
        void onChanged(int num);
    }

    public interface MsgHandleInterception {

        void onChangedPassword();

        void onRefreshUnRead();
    }
}
